namespace study43 {
  /**
   * in关键字
   * 1. 在类型层面用于构造类型
   * 2. 在运行时用于判断对象属性是否存在
   */

  // 1. 简单的映射类型
  type Person = {
    name: string;
    age: number;
    isEmployed: boolean;
  }

  type PartialPerson = {
    [k in keyof Person]?: Person[k]
  }

  // 等同于
  // type PartialPerson = {
  //   name?: string | undefined;
  //   age?: number | undefined;
  //   isEmployed?: boolean | undefined;
  // }

  // 2. 映射类型与联合类型
  type Keys = "name" | "age" | "isEmployed";

  type Person1 = {
    [k in Keys]: string | number | boolean;
  }

  // 等同于
  // type Person1 = {
  //   name: string | number | boolean;
  //   age: string | number | boolean;
  //   isEmployed: string | number | boolean;
  // }

  type Person2 = {
    [k in Keys]: Person[k];
  }

  // 等同于
  // type Person2 = {
  //   name: string;
  //   age: number;
  //   isEmployed: boolean;
  // }

  // 3. 条件类型中的 in
  type Messageof<T> = T extends { message: unknown } ? T['message'] : never

  type Email = { message: string; from: string };
  type SMS = { message: string; phoneNumber: string };
  type Chat = { content: string };

  type EmailMessage1 = Messageof<Email>; // string
  type SMSMessageContents = Messageof<SMS>; // string
  type ChatMessageContents = Messageof<Chat>; // never

  // 4. 运行时的 in
  let person = {
    name: "Alice",
    age: 30
  }

  console.log('name' in person);  // true
  console.log('gender' in person);  // false

  // 5. 实战案例
  // 5.1 条件类型结合 in
  type Bird = { fly: () => void }
  type Fish = { swim: () => void }

  function move(animal: Bird | Fish) {
    if ('fly' in animal) {
      animal.fly()
    } else {
      animal.swim()
    }
  }

  // 5.2 创建部分类型
  type Pick<T, K extends keyof T> = {
    [P in K]: T[P]
  }

  type Person4 = {
    name: string;
    age: number;
    gender: string;
  }

  type NameAndAge = Pick<Person4, 'name' | 'age'>
}